/****************** Copyright(c) HDM  ***********************
* 
*------File Info--------------------------------------------------------------
* File Name: Task_ADC
* Latest modified Date: 最终修改日期（YYYY-MM-DD）
* Latest Version:       最终修订版本号
* Description:          文件的简要描述信息
* compiler:             MDK v4.74
* MCU:                  STM32F103VE
* Oscillator Crystal Frequency:    8MHz
*-----------------------------------------------------------------------------
* Created By:    文件的创建者姓名
* Created date:  文件的创建日期（YYYY-MM-DD）
* Version:       文件创建时的版本号
* Descriptions:  文件创建时的简要描述
*
*-----------------------------------------------------------------------------
* Modified by:   修改人的姓名
* Modified date: 文件的修改日期（YYYY-MM-DD）
* Version:       文件修订的版本号
* Description:   文件修订的简要描述
*
******************************************************************************/


/* Includes -----------------------------------------------------------------*/
#include "stdint.h"                    /* data type definitions and macro*/
#include "stm32f1xx_hal.h"
#include "string.h"
#include "cmsis_os.h"
#include "Task_ADC.h"
#include "tim.h"
#include "adc.h"
#include "iwdg.h"

#include "../../Drivers/BSP/bsp_user_lib.h"


#define ADC_EN 1
#if ADC_EN

/* Private typedef ----------------------------------------------------------*/
/* Private define -----------------------------------------------------------*/
#define AIN_CHANNEL_NUM                8    /* 模拟通道数量 */
#define ADC_FIFO_SIZE                  200   /* ADC FIFO缓存区大小(ADC_FIFO_TRIM*2 < 范围 < 65535)*/
#define ADC_FIFO_TRIM                   10   /* 前后各修剪的数量 (0~1000太大没意义)*/
#define ADC_SAMPLE_PERIOD_MS           5    /* ADC采样周期,单位ms */
/* Private macro ------------------------------------------------------------*/
/* Private constants ------------------------------------------------------- */
/* Private variables --------------------------------------------------------*/
/* Private function prototypes ----------------------------------------------*/
static void Timer4Config(uint16_t _period);
/* Forward Declaration of local functions -----------------------------------*/
/* Declaration of extern functions ------------------------------------------*/
/* Global variables ---------------------------------------------------------*/
/* ADC变量 */
__IO uint16_t AdcValue[AIN_CHANNEL_NUM];                             /* ADC变量,DMA自动存入该变量 */
__IO uint16_t AdcValueFifo[AIN_CHANNEL_NUM][ADC_FIFO_SIZE];          /* ADC值FIFO缓冲区 */
__IO uint16_t AdcValueFifoCnt = 0;                                   /* 指向ADC值FIFO缓冲区位置 */
//__IO int32_t AinValue[8];                                            /* 保存ADC通道采样、滤波、转换后的值,为实际值放大1000000倍,单位uV和uA*/
float __IO AinValue[8];
__IO uint8_t ChannelState[8];                                        /* 各通道开关量状态(通过阈值g_tParam.threshold判断) */
float ADC_Value[8];                                 /*8模拟量通道值，经过公式换算和外部校准系数k b校准后的最终污染物浓度值*/
/* 看门狗和任务监测的相关变量 */
uint8_t IwdgRefreshEn = 1;                                           /* 使能独立看门狗刷新功能 */
uint8_t ADCFlag=0;

/* 模拟通道量程类别 */
const uint8_t AIN_Range[AIN_CHANNEL_NUM] =
        {
                1, 1, 1, 1, 1,1,1,1
        };

void Minutes_CUSUM(void);

/** @defgroup Application_Functions
  * @{
  */
/**
  * @brief  Timer4Config function 
  *         不使用CubeMX生成的定时器初始化函数，采用此函数进行初始化
  * @param  _period 定时周期/ms(1-6000ms)
  * @retval None
  */
static void Timer4Config(uint16_t _period) {
    htim4.Instance = TIM4;
    htim4.Init.Prescaler = HAL_RCC_GetHCLKFreq() / 10000 - 1;         /* 100us*/
    htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim4.Init.Period = _period * 10 - 1;
    htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    if (HAL_TIM_Base_Init(&htim4) != HAL_OK) {
        Error_Handler();
    }

    /* 添加部分 */
    //HAL_TIM_GenerateEvent(&htim5,TIM_EVENTSOURCE_UPDATE);
    __HAL_TIM_CLEAR_IT(&htim4, TIM_IT_UPDATE);                       /* 关键部分 要想在中断中关闭定时器,必须在启动定时器前要先清除标志位,暂时不知道原因 */
    HAL_TIM_Base_Start_IT(&htim4);
}

/**
  * @brief This function is called to increment  a global variable "uwTick"
  *        used as application time base.
  * @note In the default implementation, this variable is incremented each 1ms
  *       in Systick ISR.
  * @note 替代系统的函数,增加自己的内容
  * @retval None
  */
void Task_AdcInit(void) {
    /* 配置在定时器4采样ADC值 */
    Timer4Config(ADC_SAMPLE_PERIOD_MS);
}

/**
  * @brief This function is called to sample adc vaule.
  * @note 在定时器4中断中调用此函数. 
  * @retval None
  */
void AdcSample(void) {
    uint8_t i;
    /* 把ADC值存入FIFO中 */
    for (i = 0; i < AIN_CHANNEL_NUM; i++) {
        AdcValueFifo[i][AdcValueFifoCnt] = AdcValue[i];
    }

    if (++AdcValueFifoCnt >= ADC_FIFO_SIZE) {
        AdcValueFifoCnt = 0;
    }
}

/**
  * @brief  ADC值转换为量程值功能函数
  *         转换后的值为实际值放大1000000倍,单位uV和uA
  * @param  None
  * @retval None
  */
int32_t AdcConvert(uint8_t cmd, uint16_t val) {
    int32_t rst;

    switch (cmd) {
        case 1:                                                          // 0~+10V 公式:Value/4095*2.5(基准电压)/运放放大系数(1/4)*1000000(放大为uV)
            rst = val * 2442;                                            //uV
            break;
        case 2:                                                          // -10V~+10V
            rst = 4882 * ((int16_t) val - 2048);
            break;
        case 3:                                                          // 0~5V
            rst = val * 1221;                                            //uV
            break;
        case 4:                                                          // -5V~+5V
            rst = 2441 * ((int16_t) val - 2048);
            break;
        case 5:                                                          // 0~+20mA
            rst = 20000 * (uint32_t) val / 4095;
//        rst = 14140 * (uint32_t)val / 4095;/* 交流有效值 */
            break;
        case 6:                                                          // -20mA~+20mA
            rst = 9765 * ((int16_t) val - 2048);
            break;
        default:
            rst = 0;
            break;
    }

    return rst;
}

/**
  * @brief  ADC sample task function 
  *         该任务每秒执行一次 
  * @param  None
  * @retval None
  */
void Task_ADC(void const *argument) {
    static uint8_t i, j;
    static uint32_t xLastWakeTime;
    static uint32_t sum;
    static float data, tempt;
    static uint16_t array_temp[ADC_FIFO_SIZE];                       /* 排序临时存储区 */
#if 0
    static char str_tmp[200];
#endif

    /* Run the ADC calibration */
    if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK) {
        /* Calibration Error */
        Error_Handler();
    }

    HAL_ADC_Start_DMA(&hadc1, (uint32_t *) AdcValue, 8);

    Task_AdcInit();

    /* 变量xLastWakeTime需要被初始化为当前心跳计数值。说明一下，这是该变量唯一一次被显式赋值。之后，
        xLastWakeTime将在函数vTaskDelayUntil()中自动更新。 */
    xLastWakeTime = xTaskGetTickCount();


    for (;;) {
//        HAL_RTC_GetTime(&hrtc, &TimeCurrent, RTC_FORMAT_BIN);

        /************************ ADC部分 *************************/
        /** 目前仅测电流通道4-7,通道指示灯控制对应输出通道4-7 *       */
        for (i = 0; i < 8; i++) {
            /* 拷贝到临时存储区,并进行排序  ADC_FIFO_SIZE=200  */
            for (j = 0, sum = 0; j < ADC_FIFO_SIZE; j++) {
                array_temp[j] = AdcValueFifo[i][j];
            }
            bubble_sort_uint16_t(array_temp, ADC_FIFO_SIZE);

            /* 除去修剪部分,计算平均值 */
            for (j = ADC_FIFO_TRIM, sum = 0; j < (ADC_FIFO_SIZE - ADC_FIFO_TRIM);) {
                sum += array_temp[j++];
            }
            sum /= (ADC_FIFO_SIZE - (ADC_FIFO_TRIM << 1));

            AinValue[i] = AdcConvert(AIN_Range[i], sum);

            /* 禁止采集标志位如果为0,则采集数据为0 */
//            if ((g_tParam.SystemFlag & (uint32_t)1) == 0)
//            {
//                 AinValue[i] = 0;
//            }
        }
#if 0
        /* 打印ADC值 */
        sprintf(str_tmp, "Adc: %d  %d  %d  %d  %d  %d  %d  %d\r\n",
                AdcValue[0], AdcValue[1], AdcValue[2], AdcValue[3], AdcValue[4], AdcValue[5], AdcValue[6], AdcValue[7]);
        comSendString(COM2, str_tmp);

        sprintf(str_tmp, "AIN Value: %fmV  %fmV  %fmV  %fmV  %fmA  %fmA  %fmA  %fmA\r\n",
                AinValue[0]/1000, AinValue[1]/1000, AinValue[2]/1000, AinValue[3]/1000, AinValue[4]/1000, AinValue[5]/1000, AinValue[6]/1000, AinValue[7]/1000);
        comSendString(COM2, str_tmp);
#endif


//        /* 延时1秒 */
//        osDelayUntil(&xLastWakeTime, 1000);
//        Timer_OneSecondCallback();                                   /* 秒计时单位更新 */
//        GprsTimer();                                                 /* GPRS的定时器 */
//        HAL_GPIO_TogglePin(LED1_GPIO, LED1_PIN);

//温度4-20mA 0-100℃  y=6.25x-25
        data = AinValue[4] / 1000;              //uA转换成mA
        tempt = data;
        tempt = tempt * 6.25;    //外部校准系数k
        tempt = tempt - 25;     //外部校准系数b
        ADC_Value[4] = tempt;
        //	ADC_Value[4]=20.2;
        if (ADC_Value[4] < 0) ADC_Value[4] = 0;
        if (ADC_Value[4] > 100) ADC_Value[4] = 100;


        ADCFlag = 1;    //ADC数据采集成功标记

        if (IwdgRefreshEn) {
            HAL_IWDG_Refresh(&hiwdg);                                    /* 喂独立看门狗 */
        }
    }
}

#endif

/*----------------------------------------------------------------------------
 * end of file
 *---------------------------------------------------------------------------*/
/************** (C) COPYRIGHT HDM  ********END OF FILE****/
